<?php


namespace Lib\Model;


class Model extends Base
{
    // 原始数据，数据库查到的结果
    protected $data = array();
    // 新数据，即将变更的数据
    protected $newData = array();
    // 表名
    protected static $table = '';
    // 字段列表
    protected static $fields = array();
    // 主键字段
    protected static $primary = '';
    // 是否存在数据库
    protected $exist = false;

    /**
     * 保存
     * @return bool
     * @throws \ErrorException
     */
    public function save()
    {
        // 已有数据保存执行更新
        if ($this->exist) {
            return $this->update();
        }
        // 顺序拼接sql
        $keys = array();
        $values = array();
        foreach ($this->newData as $key => $value) {
            $keys[] = '`'.$key.'`';
            $values[] = '?';
        }
        $sql = "INSERT INTO " . static::$table . "(". implode(',', $keys) .") VALUES (". implode(',', $values) .")";
        $insert_id = self::executeInsert($sql, $this->newData, $error);
        if (!$insert_id) {
            throw new \ErrorException($error);
        }
        // 插入成功替换原始数据
        $this->data = $this->newData;
        $this->newData = array();
        return $insert_id;
    }

    /**
     * 删除
     * @return bool
     * @throws \ErrorException
     */
    public function delete()
    {
        $sql = "DELETE FROM " . static::$table . " WHERE " . static::$primary . " = ?";
        $result = self::executeDelete($sql, array(static::$primary => $this->data[static::$primary]), $error);
        if ($result === false) {
            throw new \ErrorException($error);
        }
        return $result;
    }

    /**
     * 更新
     * @return bool
     * @throws \ErrorException
     */
    public function update()
    {
        // 原始数据和新数据合并
        $fdata = array_merge($this->data, $this->newData);
        // 对比合并后的数据和原始数据得到变更的数据
        $udata = array_diff($fdata, $this->data);
        if (count($udata) == 0) {
            return false;
        }
        // 主键值不作为更新内容
        unset($udata[static::$primary]);
        // 顺序拼接sql
        $keys = array();
        foreach ($udata as $key => $value) {
            $keys[] = '`'.$key.'`=?';
        }
        // 占位参数
        $udata[] = $this->data[static::$primary];
        $sql = "UPDATE " . static::$table . " SET " . implode(',', $keys) . " WHERE " . static::$primary . " = ?";
        // 执行update语句
        $result = self::executeUpdate($sql, $udata, $error);
        if ($result === false) {
            throw new \ErrorException($error);
        }
        // 更新成功替换原始数据
        $this->data = $fdata;
        $this->newData = array();
        return $result;
    }

    /**
     * 通过主键值获取数据
     * @param $id
     * @return |null
     * @throws \ErrorException
     */
    public static function find($id)
    {
        $sql = "SELECT * FROM " . static::$table . " WHERE " . static::$primary . " = ? LIMIT 1";
        $result = static::executeSelect($sql, array($id), $error);
        if ($result === false) {
            throw new \ErrorException($error);
        }
        return count($result) > 0 ? $result[0] : null;
    }

    /**
     * 创建应该user模型，可以带数据创建，也可以先创建后设置数据
     * Model constructor.
     * @param null $data
     */
    public function __construct($data = null)
    {
        if ($data != null) {
            $this->rigout($data);
        }
    }

    /**
     * 装配数据
     * @param $data
     */
    protected function rigout($data)
    {
        foreach ($data as $key => $value) {
            if (in_array($key, static::$fields)) {
                $this->data[$key] = $value;
            }
        }
        $this->exist = true;
    }

    /**
     * 设置主键值后，重新装配数据
     * @return bool
     */
    public function reRigout()
    {
        if (isset($this->newData[static::$primary]) && $this->newData[static::$primary]) {
            try {
                $result = static::find($this->newData[static::$primary]);
                $this->rigout($result);
                $this->newData = array();
                return true;
            } catch (\ErrorException $e) {
                return false;
            }
        }
        return false;
    }

    public function __get($name)
    {
        if (in_array($name, static::$fields) && isset($this->data[$name])) {
            return $this->data[$name];
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, static::$fields)) {
            $this->newData[$name] = $value;
        }
    }
}